package org.phalanx.server.ServerCache;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
/*
BlueWave Inventory Manager
Copyright (C) 2007 Steven Day

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

/*
 * Cache object is designed as a container for objects that will be loaded into the server
 * from various sources such as mySQL, a file, or the server itself. The Cache object will 
 * usually be accessed through the CacheManager and be given a name. For example
 * a Cache that stores all the usernames and passwords may be called "UserPassCache" and can
 * be invoked by BlueWaveServer.getCacheHandler().getCache("UserPassCache");
 * 
 * The Cache itself will usually get accessed much like a Hashtable with:
 * 
 * Cache c = BlueWaveServer.getCacheHandler().getCache("UserPassCache");
 * String password = (String)c.getValue("User1");
 * 
 * Please note that the key can be an object of any type and the String key is just an example
 */

public class Cache {
	private Hashtable<Object, Cacheable> internalCacheTable;
	private String cacheName;
	//	isCleared : internal flag for if a cache has been cleared
	// in which we will halt any action done on the cache until 
	// the cache has been repopulated. This should really only be invoked
	// upon a refresh as improper use of this flag can lead to a lock and server freeze
	private boolean isCleared = false;
	// clearedAllowed informs whether a cache is allowed to be refreshed or if it is locked
	// from a refresh. This is useful if a cache holds important system data that may corrupt
	// server operations etc. but will usually be set to true
	private boolean clearedAllowed = true;
	
	public Cache (String cName){
		cacheName = cName;
		initializeCacheTable();
	}
	
	public Cache (String cName, boolean canClear){
		cacheName = cName;
		clearedAllowed = canClear;
		initializeCacheTable();
	}
	
	private void initializeCacheTable(){
		internalCacheTable = new Hashtable<Object,Cacheable>();
	}
	
	public void setCacheName(String cName){
		cacheName = cName;
	}
	
	public String getCacheName(){
		return cacheName;
	}
	
	public Hashtable<Object,Cacheable> getInternalCacheTable(){
		return internalCacheTable;
	}
	
	public void put(Object key, Cacheable value){
		if (key != null){
			if (!isCleared){
				internalCacheTable.put(key, value);
			}
		}
	}
	
	public void delete(Object key){
		if (key != null){
			if (!isCleared){
				internalCacheTable.remove(key);
			}
		}
	}
	
	public Cacheable get(Object key){
		Cacheable cacheValue = null;
		
		if (!isCleared && internalCacheTable.containsKey(key)){
			cacheValue = internalCacheTable.get(key);
		}
		
		return cacheValue;
	}
	
	public boolean isCleared(){
		return isCleared && clearedAllowed;
	}
	
	// Do not use this function unless you know what you are doing
	// If you want to blank the Cache just invoke the
	// reLoad(new HashTable);
	
	protected boolean clearCache(){
		boolean isSuccess = false;
		if (clearedAllowed && !isCleared){
			isCleared = true;
			internalCacheTable.clear();
			isSuccess = true;
		}
		return isSuccess;
	}
	
	public boolean isClearAllowed(){
		return clearedAllowed;
	}
	
	public boolean reLoad(Hashtable<Object,Cacheable> loadTable){
		boolean isSuccess = false;
		
		if (clearCache()){
			internalCacheTable = new Hashtable<Object,Cacheable>(loadTable);
			isSuccess = unLockClear();
		}
		
		return isSuccess;
	}
	
	// Do not use this function unless you know what you are doing!!!
	protected boolean unLockClear(){
		boolean isSuccess = false;
		if (isCleared){
			isCleared = false;
			isSuccess = true;
		}
		return isSuccess;
	}
	
	public ArrayList<Object> getKey(Object value){
		ArrayList<Object> ListOfKeys = new ArrayList<Object>();
		
		Enumeration<Object> e = internalCacheTable.keys();
		
		while (e.hasMoreElements()){
			Object currentKey = e.nextElement();
			if ((internalCacheTable.get(currentKey) == null && value == null) || 
					(currentKey != null && 
							internalCacheTable.get(currentKey).equals(value))){
				ListOfKeys.add(currentKey);
			}
		}
		
		return ListOfKeys;
	}
	
	public Object getFirstKey(Object value){
		Object firstKey = null;
		ArrayList<Object> ListOfKeys = getKey(value);
		
		if (ListOfKeys.size() > 0){
			firstKey = ListOfKeys.get(0);
		}
		
		return firstKey;
	}
	
}
